<?php
/*
 * author:zengguozong
 * */
namespace WeChatDeveloper\app;
use  WeChat\Oauth;
use think\Cache;
use think\Db;
use app\common\lib\Aes;
class MiniLogin {
    /*
     * 功能简介:扩展WeChatDeveloper
     * 1.用户小程序登录获得加密的userinfo , session_key , code , iv=>发送到服务端
     * 2.服务端根据iv , code , session_key ，对微信服务器加密的userinfo 解密 得到 userinfo信息,unionid[多个小程序同识别码]
     * 3.服务端缓存openid=>对应用户信息值，返回根据openid  aes加密的 token ,服务端可以从token aes解密得到 openid  拿到对应的缓存用户信息值。
     * 4.token的实效为7100秒,每使用一次返回新的，当过期时小程序需重新wx.login()方法中重新与服务端交互获取token
    */
    public function __construct($config){
        //token加密配置:AES-128-CBC
        $this->key = "abcdefg123456";
        $this->iv = "1234567890888888";
        //是否开启aes传输加密
        $this->api_auth = false;
        //token过期时间
        $this->expire_time = $config['expire_time'];
        //初始化小程序配置
        $this->config = $config ;
        require __DIR__.'/../include.php';
        //如果认证token不正确||或者认证token为空时 未传输[code,iv,encryptedData]
        $new_token = $this->encode_key(input('token'));

        if(!$new_token){
            echo json_encode(array('code'=>401,'data'=>time(),'msg'=>'用户认证失败。'),JSON_UNESCAPED_UNICODE);
            die();
        }
    }


    //小程序认证登录，并返回用户微信信息
    public function mini_auth(){
        $debug = input('debug');
        $config = $this->config;
        /*######1.获取用户的code 微信端返回的iv 与加密数据 传输后端得到sessionKey 和 openid ,微信用户信息 #####*/
        $mini =  new   Oauth($config);
        //用户code
        $code =  $config['code'];//用户code
        $iv = $config['iv'];//加密 向量
        $decode=  $config['encryptedData'];//加密的数据

        if(empty($code)||empty($iv)||empty($decode)){
            echo json_encode(array('code'=>400,'data'=>'','msg'=>'code或者iv或者encryptedData为空。'),JSON_UNESCAPED_UNICODE);
            die();
        }
        try {
            $userInfo_decode = $mini->userInfo($code, $iv, $decode);//获取用户数据
        } catch (\Exception $e) {
            echo json_encode(array('code'=>400,'data'=>'','msg'=>$e->getMessage()),JSON_UNESCAPED_UNICODE);
            die();
        }

        //比对数据库用户数据是否已经添加
        $data['avatarurl'] = $userInfo_decode['avatarUrl'];//头像
        $data['province'] = $userInfo_decode['province'];//省份
        $data['city'] = $userInfo_decode['city'];//城市
        $data['country'] = $userInfo_decode['country'];//乡村
        $data['gender'] = $userInfo_decode['gender'];//男女
        $data['nickname'] = $userInfo_decode['nickName'];//姓名
        $data['openid'] = $userInfo_decode['openid'];//openid
        $data['session_key'] = $userInfo_decode['session_key'];
        $data['unionid'] = $userInfo_decode['unionId'];
        $data['wx_phone'] = "";//用户的手机号码
        try{
            //存入微信信息表:
            $condition['openid'] = $data['openid'] ;
            $wx_user_info =  Db::name('wx_users')->where($condition)->find();
            if(!empty($wx_user_info['uid'])){
                $aes = new Aes();
                $encry['uid'] = $aes->encrypt($wx_user_info['uid']);
            }
            if($debug==1){
                $this->server_log('数据库微信数据:');
                $this->server_log(json_encode($wx_user_info));
                $this->server_log('微信服务器返回数据与所要加密数据:');
                $this->server_log(json_encode($userInfo_decode));
            }
            if(empty($wx_user_info)){
                //客户端
                if($this->config['appid'] =="wxe021e332611a4f12"){
                    $data['form'] = 1;
                }
                //门店
                if($this->config['appid'] =="wx4d60c5e3fece4a6d"){
                    $data['form'] = 3;
                }
                $result =  Db::name('wx_users')->insert($data);//添加
                if($debug==1) {
                    $this->server_log('数据库微信数据为空:');
                    $this->server_log('所添加的数据:');
                    $this->server_log(json_encode($data));
                    $this->server_log('添加结果:'.$result);
                }
                $data['uid'] = '';
            }
            if(!empty($wx_user_info)){
                if($debug==1){
                    $this->server_log('数据库微信数据不为空:');
                }
                $user_condition['uid'] = $wx_user_info['uid'];
                $user_info =  Db::name('user')->where($user_condition)->find();
                if($debug==1) {
                    $this->server_log('数据库用户表数据:');
                    $this->server_log(json_encode($user_info));
                }
                $wx_user_info['role'] = $user_info['role'];
                $userInfo_decode['role'] = $user_info['role'];
                $data['role'] = $wx_user_info['role'];

                $up_wx_info = $data ;
                $userInfo_decode['uid'] = $wx_user_info['uid'];
                $data['uid'] = $encry['uid'];
                $data['wx_phone'] = $wx_user_info['wx_phone'];

                //客户端
                if($this->config['appid'] =="wxe021e332611a4f12"){
                    $up_wx_info['form'] = 1;
                }
                //门店
                if($this->config['appid'] =="wx4d60c5e3fece4a6d"){
                    $up_wx_info['form'] = 3;
                }
                if($debug==1) {
                    $this->server_log('data:');
                    $this->server_log(json_encode($data));
                    $this->server_log('加密数据:');
                    $this->server_log(json_encode($userInfo_decode));
                    $this->server_log('更新数据:');
                    $this->server_log(json_encode($up_wx_info));
                    $this->server_log('条件:');
                    $this->server_log(json_encode($condition));
                }
                Db::name('wx_users')->where($condition)->setField('avatarurl',$up_wx_info['avatarurl']);;//更新微信信息
                Db::name('wx_users')->where($condition)->setField('province',$up_wx_info['province']);;//更新微信信息
                Db::name('wx_users')->where($condition)->setField('city',$up_wx_info['city']);;//更新微信信息
                Db::name('wx_users')->where($condition)->setField('country',$up_wx_info['country']);;//更新微信信息
                Db::name('wx_users')->where($condition)->setField('nickname',$up_wx_info['nickname']);;//更新微信信息
                Db::name('wx_users')->where($condition)->setField('openid',$up_wx_info['openid']);;//更新微信信息
                Db::name('wx_users')->where($condition)->setField('gender',$up_wx_info['gender']);;//更新微信信息
                Db::name('wx_users')->where($condition)->setField('wx_phone',$up_wx_info['wx_phone']);;//更新微信信息
                Db::name('wx_users')->where($condition)->setField('unionid',$up_wx_info['unionid']);;//更新微信信息
                Db::name('wx_users')->where($condition)->setField('session_key',$up_wx_info['session_key']);;//更新微信信息
                Db::name('wx_users')->where($condition)->setField('form',$up_wx_info['form']);;//更新微信信息
            }
            if(isset($wx_user_info['unionId'])){
                $data['unionid'] = $wx_user_info['unionId'];
            }
            //如果已注册,检测user信息表,返回user表信息
            /*
            if(!empty($wx_user_info['uid'])){
                $user_condition['uid'] = $wx_user_info['uid'];
                $user_info = Db::name('user')->where($user_condition)->find();
                $userInfo_decode['user_info'] = $user_info ;
            }
            */
        } catch (\Exception $e) {
            file_put_contents( "minierror.txt", PHP_EOL, FILE_APPEND);
            file_put_contents( "minierror.txt", "用户信息:".PHP_EOL, FILE_APPEND);
            file_put_contents( "minierror.txt", json_encode($wx_user_info).PHP_EOL, FILE_APPEND);
            file_put_contents( "minierror.txt", json_encode($data).PHP_EOL, FILE_APPEND);
            file_put_contents( "minierror.txt", date("Y-m-d H:i:s").PHP_EOL, FILE_APPEND);
            file_put_contents( "minierror.txt", "小程序登录错误信息".$e->getMessage().PHP_EOL, FILE_APPEND);
        }
        if($debug==1){
            $this->server_log('最终加密数据:');
            $this->server_log(json_encode($userInfo_decode));
        }
        $token = $this->decode_key($userInfo_decode);//根据openid生产token
        $data['token'] = $token ;
        $data['expire_time_stamp'] = (time() + $this->expire_time)*1000;
        echo json_encode(array('code'=>200,'data'=>$data,'msg'=>'获取token成功。'),JSON_UNESCAPED_UNICODE);
        die();
    }

    /*
     * 根据openid生成 加密token , 前端缓存在小程序Wx.setStorage 中
     * @param $openid :设置缓存名为openid加密
     * @param $value  :设置该缓存名的值
     * */
    public function decode_key($userInfo_decode,$old_token=null){
        $token = $this->encrypt($userInfo_decode['openId'].time());
        if(!empty($old_token)){
            Cache::rm($old_token);//删除旧的
        }
        $debug = input('debug');
        if($debug==1){
            $this->server_log('正在加密的数据:');
            $this->server_log(json_encode($userInfo_decode));
        }
        Cache::set($token,json_encode($userInfo_decode),$this->expire_time);//token设置时间为7100秒
        return $token ;//返回新的
    }

    //前端认证时传输该 加密token , 后端解密 该token 得到用户openid
    public function encode_key($token){
        //解决url转码过程中+变成空格的问题
        $token = str_replace(' ','+',$token);


        //如果认证token为空=>小程序认证登录+生产token
        if(empty($token)){
            return $this->mini_auth();
        }
        //如果认证token不为空=>检测token是否正确或过期，正确返回新token，过期或错误则返回验证错误，前端重新认证
        else{
            $debug = input('debug');
            $value = Cache::get($token);//得到对应openid存储的数据
            if($debug==1){
                $this->server_log('调试模式开启:');
                $this->server_log('token:');
                $this->server_log($token);
                $this->server_log('value:');
                $this->server_log($value);
                die();
            }
            //缓存不为空,验证用户数据签名,返回用户数据,
            if(!empty($value)){
                if($this->api_auth){
                    $param = input();
                    // 1、按字段排序
                    ksort($param);
                    // 2、拼接成字符串数据
                    $string = http_build_query($param);
                    // 3、加密
                    $this->key = "dfsfdc15623xz";
                    $this->iv = "1234567890666666";
                    $sign =  $this->encrypt($string);
                    if($sign==input('sign')){
                        return true;
                    }
                    else return false;
                }
                else return true;
            }
            //缓存为空，认证错误
            else{
                return false;
            }
        }
    }

    //open_ssl加密 or mcrypt_encrypt加密
    public  function encrypt($data){
        if(version_compare(PHP_VERSION,'5.6.0', '>=')){
            return base64_encode(openssl_encrypt($data,"AES-128-CBC",$this->key,OPENSSL_RAW_DATA,$this->iv));
        }
        else{
            $encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $this->key, $data, MCRYPT_MODE_CBC, $this->iv);
            return base64_encode($encrypted);
        }
    }
    //open_ssl解密 or mcrypt_encrypt解密
    public  function decrypt($data){
        if(version_compare(PHP_VERSION,'5.6.0', '>=')){
            return openssl_decrypt(base64_decode($data),"AES-128-CBC",$this->key,OPENSSL_RAW_DATA,$this->iv);}
        else{
            $decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $this->key, base64_decode($data), MCRYPT_MODE_CBC,$this->iv);
            return rtrim($decrypted, "\0");
        }
    }
    //服务器日志
    public function server_log($str=''){
        echo $str."</br>";
        //file_put_contents( "runking.txt", $str.PHP_EOL, FILE_APPEND);
    }

}